﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

using Shared;

namespace ClusterServer
{
    class Program
    {
        #region Fields

        /// <summary>
        /// Main configuration.
        /// </summary>
        public static Configuration Config;

        /// <summary>
        /// Log handler.
        /// </summary>
        public static LogHandler Logger;

        /// <summary>
        /// Session manager.
        /// </summary>
        public static SessionManager SessionManager;

        /// <summary>
        /// Database manager.
        /// </summary>
        public static DatabaseManager DatabaseManager;

        /// <summary>
        /// Client manager.
        /// </summary>
        public static ClientManager ClientManager;

        /// <summary>
        /// Network handler.
        /// </summary>
        public static NetworkHandler Network;

        /// <summary>
        /// Cluster manager.
        /// </summary>
        public static ClusterManager ClusterManager;

        /// <summary>
        /// Specifies wether to end the WaitForExit loop because of error or not.
        /// </summary>
        public static bool Error = false;

        /// <summary>
        /// Name of the current server module.
        /// </summary>
        public const string Module = "ClusterServer";

        #endregion

        #region Methods

        /// <summary>
        /// Main program loop.
        /// </summary>
        static void Main()
        {
            WindowUtil.DisableCloseButton();

            TitleMonitor.Initialize(Module);
            TitleMonitor.Start();

            GarbageCollection.Start();

            Console.WriteLine();
            Console.WriteLine("   Initialization has been started.");
            Console.WriteLine();

            try
            {
                Logger = new LogHandler(Module);
                Program.Logger.Write(LogType.Notice, "LogHandler has been initialized.");

                Config = new Configuration("Configuration\\" + Module + ".conf");
                Program.Logger.Write(LogType.Notice, "Configuration has been loaded.");

                SessionManager = new SessionManager();
                Program.Logger.Write(LogType.Notice, "SessionManager has been initialized.");

                DatabaseManager = new DatabaseManager();
                Program.Logger.Write(LogType.Notice, "DatabaseManager has been initialized.");

                ClientManager = new ClientManager();
                Program.Logger.Write(LogType.Notice, "ClientManager has been initialized.");

                Network = new NetworkHandler("Any", 28000, new AsyncCallback(Program.ClientManager.HandleConnection));
                Program.Logger.Write(LogType.Notice, "NetworkHandler has been initialized.");

                ClusterManager = new ClusterManager();
                Program.Logger.Write(LogType.Notice, "ClusterManager has been initialized.");
            }
            catch (Exception e)
            {
                Program.Logger.Write(LogType.Fatal, "Failed to initialize core.");
                Program.Logger.Crash(e);

                Environment.Exit(0);
            }

            Console.WriteLine();
            Console.WriteLine("   Initialization has been completed.");
            Console.WriteLine();

            try
            {
                ClusterManager.Add();
                Program.Logger.Write(LogType.Notice, "Cluster has been added to server pool.");

                Network.Start();
                Program.Logger.Write(LogType.Notice, "Listening for incoming clients.");
            }
            catch (Exception e)
            {
                Program.Logger.Write(LogType.Fatal, "Failed to start services.");
                Program.Logger.Crash(e);

                Program.Error = true;
            }

            Console.WriteLine();
            Console.WriteLine("   Output has been started.");
            Console.WriteLine();

            WaitForExit();

            Console.WriteLine();
            Console.WriteLine("   Exit handling has been started.");
            Console.WriteLine();

            try
            {
                ClusterManager.Remove();
                Program.Logger.Write(LogType.Notice, "Cluster has been removed from server pool.");

                Network.Stop();
                Program.Logger.Write(LogType.Notice, "Stopped listening for incoming clients.");
            }
            catch (Exception e)
            {
                Program.Logger.Crash(e);
            }

            Console.WriteLine();
            Console.WriteLine("   Exit handling has been completed.");
            Console.WriteLine();

            Environment.Exit(0);
        }

        /// <summary>
        /// Waits for escape button press.
        /// </summary>
        private static void WaitForExit()
        {
            ConsoleKeyInfo KeyPressed = Console.ReadKey(true);

            if (KeyPressed.Key == ConsoleKey.Escape || Program.Error)
            {
                return;
            }
            else
            {
                WaitForExit();
            }
        }

        #endregion
    }
}
